package picounit.java.type;

import java.util.Arrays;
import java.util.Iterator;

class SuperTypes extends picounit.java.collection.Iterable<Type> {
    public SuperTypes(Class<?> clazz) {
        super(new SuperTypesIterator(clazz));
    }

    static class SuperTypesIterator implements Iterator<Type> {
        private Class<?> superClass;
        private Iterator<Class<?>> interfaces;

        public SuperTypesIterator(Class<?> clazz) {
            this.superClass = clazz.getSuperclass();
            this.interfaces = new InterfaceIterator(clazz.getInterfaces());
        }

        public boolean hasNext() {
            if (interfaces.hasNext()) {
                return true;
            }

            if (superClass != null) {
                return true;
            }

            return false;
        }

        public Type next() {
            if (interfaces.hasNext()) {
                return new Type(interfaces.next());
            }

            if (superClass != null) {
                interfaces = new InterfaceIterator(superClass.getInterfaces());

                try {
                    return new Type(superClass);
                }
                finally {
                    superClass = superClass.getSuperclass();
                }
            }

            return null;
        }

        public void remove() {
        }
    }

    @SuppressWarnings("unchecked")
    static class InterfaceIterator implements Iterator<Class<?>> {
        private final Iterator<Class> interfaces;
        private Iterator<Class<?>> current;

        public InterfaceIterator(Class interfaces[]) {
            this.interfaces = Arrays.asList(interfaces).iterator();
        }

        public boolean hasNext() {
            if (current != null && current.hasNext()) {
                return true;
            }

            return interfaces.hasNext();
        }

        public Class<?> next() {
            if (current != null && current.hasNext()) {
                return current.next();
            }

            Class<?> next = interfaces.next();

            current = new InterfaceIterator(next.getInterfaces());

            return next;
        }

        public void remove() {
        }
    }
}
